/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_zml.htm
 *
 * Zhiqim Zml is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.zml;

import java.util.Comparator;
import java.util.List;

import org.zhiqim.kernel.constants.SignConstants;
import org.zhiqim.kernel.util.Validates;
import org.zhiqim.zml.exception.StatementException;
import org.zhiqim.zml.statement._Echo;
import org.zhiqim.zml.statement._For;
import org.zhiqim.zml.statement._Function;
import org.zhiqim.zml.statement._If;
import org.zhiqim.zml.statement._Include;
import org.zhiqim.zml.statement._Var;

/**
 * 定义ZhiqimML语句接口，有两类语句
 * 
 * 1、嵌套语句
 * @see _If             判断语句，格式为：<#if a=1>内容1<#elseif a==2>内容2<#elseif a==3>内容3<#else>其他内容<#if>
 * @see _For            迭代语句，格式为：<#for item : list></#for>
 * @see _Function       全局函数定义语句，格式为：<#function name(param1, param2)></#function>
 * 
 * 2、非嵌套语句
 * @see _Text           纯文本语句
 * @see _Var            变量定义语句，格式为：<#var i=1/>
 * @see _Echo           表达式语句，格式为：${obj.getName()}
 * @see _Include        包含语句，本身不嵌套，调用后转到父ZML进行嵌套处理，格式为<#include "/zview/include.zml"/>
 * @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
 */
public abstract class Statement implements ZmlConstants, SignConstants
{
    public static final StatementComparator COMPARATOR = new StatementComparator();
    
    private Zml zml;
    private StatementNesting parent;
    
    private String statement;
    private int beginLine;
    private int beginColumn;
    private int endLine;
    private int endColumn;
    
    private int beginIndex;
    private int endIndex;
    
    private int innerBeginIndex;
    private int innerEndIndex;
    
    /**************************************************************************/
    //定义抽象方法，子类必须实现
    /**************************************************************************/
    
    /**
     * 是否是嵌套语句
     * 
     * @return  =true表示是，=false表示不是
     */
    public abstract boolean isNesting();
    
    /**
     * 由各子类实现解析语句成不同的表达式
     * 
     * @throws StatementException
     */
    public abstract void parseStatement() throws StatementException;
    
    /**
     * 由各子类实现生成HTML代码
     * 
     * @param variableMap 变量表
     * @return HTML内容
     * @throws StatementException
     */
    public abstract String process(ZmlVariable variableMap) throws StatementException;

    /**************************************************************************/
    //父类定义的通用方法
    /**************************************************************************/
    
    /**
     * 本基类保存语句基本参数，语句由子类解析
     * 
     * @param zml           ZML对象
     * @param parent        父语句对象
     * @param statement     语句
     */
    public void setStatement(Zml zml, StatementNesting parent, String statement)
    {
        this.zml = zml;
        this.parent = parent;
        this.statement = statement;
    }
    
    /**
     * 本基类保存语句基本参数，语句由子类解析
     * 
     * @param beginIndex    起始索引
     * @param endIndex      结束索引
     */
    public void setIndexAll(int beginIndex, int endIndex)
    {
        this.beginIndex = beginIndex;
        this.endIndex = endIndex;
        
        int[] begins = StatementParser.getLineColumnNoByIndex(zml.getIndexList(), beginIndex);
        int[] ends = StatementParser.getLineColumnNoByIndex(zml.getIndexList(), endIndex);
        this.beginLine = begins[0];
        this.beginColumn = begins[1];
        this.endLine = ends[0];
        this.endColumn = ends[1];
    }
    
    /**
     * 本基类保存语句基本参数，语句由子类解析
     * 
     * @param innerBeginIndex    内部起始索引
     * @param innerEndIndex      内部结束索引
     */
    public void setIndexInner(int innerBeginIndex, int innerEndIndex)
    {
        this.innerBeginIndex = innerBeginIndex;
        this.innerEndIndex = innerEndIndex;
    }
    
    /**
     * 是否语句指令独占一行
     * 
     * @return  =true表示是，=false表示不是
     */
    public boolean isExclusiveLine() throws StatementException
    {
        //1.先比前面，查看指令前面是否是空白
        if (beginColumn > 1)
        {//前面有字符不是空白的，认为不是独占一行
            String content = parent.getPrevStatement(this);
            if (content != null)
            {
                if (content.length() < beginColumn-1)
                    return false;//嵌套里前面的语句未顶格
                
                String previous = content.substring(content.length()-(beginColumn-1));
                if (!Validates.isEmptyBlank(previous))
                    return false;
            }
        }
        
        //2.再比后面，查看指令结束之后是否为空或是换行符
        if (beginLine == endLine)
        {//在同一行查看结束是不是回车换行
            return isEndBreak();
        }
        else
        {//不在同一行直接返回true,由子类解析语句后设置
            return true;
        }
    }
    
    /**
     * 是否语句结束后被换行
     * 
     * @return  =true表示被换行或结束，=false表示未被换行，后面有数据
     */
    public boolean isEndBreak() throws StatementException
    {
        String content = parent.getNextStatement(this);
        return (content == null || content.startsWith("\r") || content.startsWith("\n"));
    }
    
    /**
     * 获取嵌套的_For语句，用于break,continue
     * 
     * @return  =null表示
     */
    public _For getNearestNestingFor()
    {
        if (this instanceof _For)
            return (_For)this;
        
        StatementNesting sp = parent;
        while (sp != null)
        {
            if (sp instanceof _For)
                return (_For)sp;
            
            if (sp instanceof Zml)
                return null;
            
            sp = ((Statement)sp).parent;
        }
        
        return null;
    }
    
    /**************************************************************************/
    //父类定义的获取参数方法
    /**************************************************************************/
    
    /** 获取ZML */
    public Zml getZml()
    {
        return zml;
    }

    /** 获取ZML路径 */
    public String getPath()
    {
        return getZml().getPath();
    }
    
    /** 获取ZML索引表 */
    public List<ZmlLineIndex> getIndexList()
    {
        return zml.getIndexList();
    }
    
    public String getStatement()
    {
        return statement;
    }

    public int getBeginIndex()
    {
        return beginIndex;
    }

    public int getEndIndex()
    {
        return endIndex;
    }

    public int getBeginLine()
    {
        return beginLine;
    }

    public int getBeginColumn()
    {
        return beginColumn;
    }

    public int getEndLine()
    {
        return endLine;
    }

    public int getEndColumn()
    {
        return endColumn;
    }

    public int getInnerBeginIndex()
    {
        return innerBeginIndex;
    }

    public int getInnerEndIndex()
    {
        return innerEndIndex;
    }

    @Override
    public String toString()
    {
        return statement;
    }
    
    /** 语句比较器 */
    private static class StatementComparator implements Comparator<Statement>
    {
        @Override
        public int compare(Statement o1, Statement o2)
        {
            return o1.getBeginIndex() - o2.getBeginIndex();
        }
    }
}
